#pragma once

#include <d3d9.h>
#include <d3dx9.h>
#include <vector>


class CGraphicsController;
class iwfSurface;

///////////////////////////////////////////////////////////////////////////////
// (helper class)
// The class represents a vertex used to render a scene
///////////////////////////////////////////////////////////////////////////////
struct CIWFMeshVertex
{
   CIWFMeshVertex(float x, float y, float z, float nx, float ny, float nz, float u, float v) 
      : m_coords(x, y, z), m_normal(nx, ny, nz), m_u(u), m_v(v) {}


   D3DXVECTOR3 m_coords;
   D3DXVECTOR3 m_normal;
   float m_u, m_v;

   static DWORD FVF;
};

///////////////////////////////////////////////////////////////////////////////
// (helper class)
// The class represents a material group that aggreagates
// surfaces that use a particular material
///////////////////////////////////////////////////////////////////////////////
class CMaterialGroup
{
private:
   CGraphicsController& m_graphicsController;

   UINT m_materialIdx;
   IDirect3DIndexBuffer9* m_indexBuffer;
   UINT m_vertexStart;
   UINT m_vertexCount;

   std::vector<ULONG> m_indices;

public:
   CMaterialGroup(CGraphicsController& graphicsController,
                  UINT materialIdx,
                  UINT vertexStart);
   ~CMaterialGroup();

   void addSurface(iwfSurface* surface, UINT lightGroupVertexCount);
   void buildBuffers();

   void render(IDirect3DDevice9& d3Device, 
               std::vector<D3DMATERIAL9>& materials);

   inline bool operator==(UINT materialIdx) const;
};


///////////////////////////////////////////////////////////////////////////////
// (helper class)
// The class represents a group of surfaces using the same texture
///////////////////////////////////////////////////////////////////////////////
class CTextureGroup
{
private:
   CGraphicsController& m_graphicsController;
   long m_textureIdx;

   std::vector<CMaterialGroup*> m_materialGroups;

public:
   CTextureGroup(CGraphicsController& graphicsController,
                 long textureIdx);
   ~CTextureGroup();

   void render(IDirect3DDevice9& d3Device,
               std::vector<IDirect3DTexture9*>& textures,
               std::vector<D3DMATERIAL9>& materials);

   CMaterialGroup* findMaterialGroup(UINT materialIdx);

   void addMaterialGroup(CMaterialGroup* materialGroup);

   inline bool operator==(long textureIdx) const { return (m_textureIdx == textureIdx); }

   void buildBuffers();
};
